﻿using System;
using System.Collections.Generic;
using System.Text;

namespace RayTrace
{
    class Camera
    {
        private Point3D lowerLeftCorner;
        private Vector3D horizontal;
        private Vector3D vertical;
        private Point3D origin;
        private Vector3D u = new Vector3D();
        private Vector3D v = new Vector3D();
        private Vector3D w = new Vector3D();
        private double lensRadius;
        public Camera(Point3D lookfrom, Point3D lookat, Vector3D vup, double vfov, double aspect, double aperture, double focusDist)
        {
            Vector3D u = new Vector3D();
            Vector3D v = new Vector3D();
            Vector3D w = new Vector3D();
            lensRadius = aperture / 2;
            double thete = vfov * Math.PI / 180;
            double halfHeight = Math.Tan(thete / 2);
            double halfWidth = aspect * halfHeight;
            origin = lookfrom;
            w = Vector3D.UnitVector(lookfrom - lookat);
            u = Vector3D.UnitVector(Vector3D.CrossProduct(vup, w));
            v = Vector3D.CrossProduct(w, u);
            Vector3D lowerLeftCornerTemp = origin - halfWidth * focusDist * u - halfHeight * focusDist * v - w * focusDist;
            lowerLeftCorner = new Point3D(lowerLeftCornerTemp.X, lowerLeftCornerTemp.Y, lowerLeftCornerTemp.Z);
            Horizontal = 2 * halfWidth * u * focusDist;
            Vertical = 2 * halfHeight * v * focusDist;
        }
        internal Point3D LowerLeftCorner
        {
            get => lowerLeftCorner; set => lowerLeftCorner = value;
        }
        internal Vector3D Horizontal
        {
            get => horizontal; set => horizontal = value;
        }
        internal Vector3D Vertical
        {
            get => vertical; set => vertical = value;
        }
        internal Point3D Origin { get => origin; set => origin = value; }
        public Ray GetRay(double s, double t)
        {
            Vector3D rd = lensRadius * Form1.RandomInUnitDisk();
            Vector3D offset = u * rd.X + v * rd.Y; //偏移量，为了方便用Vector表示
            return new Ray(new Point3D(origin.X + offset.X, origin.Y + offset.Y, origin.Z + offset.Z)
                , lowerLeftCorner + s * horizontal + t * vertical - origin - offset);
        }
    }
}
